/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package GameState;

import AI.ChessAlgorithm;
import AI.I3DChess;
import AI.IntegerWrapper;
import AI.MoveHistory;
import FrameWork.Global;
import FrameWork.NewCamera;
import GameObject.ChessBoard;
import GameObject.ChessPiece;
import Manager.ResourceManager;
import Manager.ResourceManager.ECHESSPIECE;
import com.jogamp.common.nio.Buffers;
import java.nio.IntBuffer;
import javax.media.opengl.GL2;
import utils.POINT;

/**
 *
 * @author trong_000
 */
public class MainGameWithAI implements IGameState{

    public ChessBoard board;
    public ChessPiece[] chessPiece;
    
    final int MW = 32, SW = 1;
    final int BWA = MW + SW * 2;
    final int XBW = BWA * 9, YBW = BWA * 10;
    private POINT[] g_pointChessman;
    private int g_iSide;
    private int[][] g_iChessmanMap;
    private int g_iChessmanSelect;
    private boolean g_bEndGame;
    private int g_iComputerSide;
    private MoveHistory g_MoveHistory;
    private POINT g_pointBoxFrom;
    private POINT g_pointBoxTo;
    private boolean[][] g_bCanMove;
    //others
    private ChessAlgorithm chess;
    private I3DChess g_3dchess;
    
    
    public MainGameWithAI(){
        init();
    }
    
    @Override
    public void init() {
        board = new ChessBoard();
        
        g_pointChessman = new POINT[32];
        for (int i = 0; i < 32; ++i) {
            g_pointChessman[i] = new POINT();
        }

        g_iSide = 0;
        g_iChessmanMap = new int[11][12];
        g_pointBoxFrom = new POINT();
        g_pointBoxTo = new POINT();
        g_bCanMove = new boolean[11][12];
        g_MoveHistory = new MoveHistory();
        //others
        chess = new ChessAlgorithm();
        
        Reset();
    }

    public void Reset() {
      
        g_pointChessman[0].x = 5;
        g_pointChessman[0].y = 11;	//King
        g_pointChessman[1].x = 4;
        g_pointChessman[1].y = 11;	//Shi
        g_pointChessman[2].x = 6;
        g_pointChessman[2].y = 11;
        g_pointChessman[3].x = 3;
        g_pointChessman[3].y = 11;	//Xiang
        g_pointChessman[4].x = 7;
        g_pointChessman[4].y = 11;
        g_pointChessman[5].x = 2;
        g_pointChessman[5].y = 11;	//Ma
        g_pointChessman[6].x = 8;
        g_pointChessman[6].y = 11;
        g_pointChessman[7].x = 1;
        g_pointChessman[7].y = 11;	//Ju
        g_pointChessman[8].x = 9;
        g_pointChessman[8].y = 11;
        g_pointChessman[9].x = 2;
        g_pointChessman[9].y = 8;	//Pao
        g_pointChessman[10].x = 8;
        g_pointChessman[10].y = 8;
        g_pointChessman[11].x = 1;
        g_pointChessman[11].y = 7;//Bing
        g_pointChessman[12].x = 3;
        g_pointChessman[12].y = 7;
        g_pointChessman[13].x = 5;
        g_pointChessman[13].y = 7;
        g_pointChessman[14].x = 7;
        g_pointChessman[14].y = 7;
        g_pointChessman[15].x = 9;
        g_pointChessman[15].y = 7;

        g_pointChessman[16].x = 5;
        g_pointChessman[16].y = 0;//King
        g_pointChessman[17].x = 4;
        g_pointChessman[17].y = 0;//Shi
        g_pointChessman[18].x = 6;
        g_pointChessman[18].y = 0;
        g_pointChessman[19].x = 3;
        g_pointChessman[19].y = 0;//Xiang
        g_pointChessman[20].x = 7;
        g_pointChessman[20].y = 0;
        g_pointChessman[21].x = 2;
        g_pointChessman[21].y = 0;//Ma
        g_pointChessman[22].x = 8;
        g_pointChessman[22].y = 0;
        g_pointChessman[23].x = 1;
        g_pointChessman[23].y = 0;//Ju
        g_pointChessman[24].x = 9;
        g_pointChessman[24].y = 0;
        g_pointChessman[25].x = 2;
        g_pointChessman[25].y = 3;//Pao
        g_pointChessman[26].x = 8;
        g_pointChessman[26].y = 3;
        g_pointChessman[27].x = 1;
        g_pointChessman[27].y = 4;//Bing
        g_pointChessman[28].x = 3;
        g_pointChessman[28].y = 4;
        g_pointChessman[29].x = 5;
        g_pointChessman[29].y = 4;
        g_pointChessman[30].x = 7;
        g_pointChessman[30].y = 4;
        g_pointChessman[31].x = 9;
        g_pointChessman[31].y = 4;
        chessPiece = new ChessPiece[32];
        for (int i = 0; i < 32; i++) {
            chessPiece[i] = new ChessPiece(ResourceManager.getInstance().getModelChessPiece(ECHESSPIECE.values()[i]), g_pointChessman[i]);
        }
        g_iSide = 0;// RED=0, BLACK =1

        FixManMap(g_iChessmanMap, g_pointChessman);
        g_pointBoxFrom.x = 0;
        g_pointBoxFrom.y = 0;
        g_pointBoxTo.x = 0;
        g_pointBoxTo.y = 0;
        g_iChessmanSelect = 32;
        g_iComputerSide = 1;
        g_bEndGame = false;
        g_MoveHistory.count = 0;

        for (int i = 0; i < 11; i++) {
            for (int j = 0; j < 12; j++) {
                g_bCanMove[i][j] = false;
            }
        }
    }

    public void FixManMap(int[][] mapt, POINT[] manpoint) {
        for (int i = 0; i < 11; i++) {
            for (int j = 0; j < 12; j++) {
                mapt[i][j] = 32;
            }
        }
        for (int i = 0; i < 32; i++) {
            if (manpoint[i].x != 0) {
                mapt[manpoint[i].x][manpoint[i].y] = i;
            }
        }
    }
    
     public void Think() {
        int i, j;
        IntegerWrapper tside;
        int[][] tmap = new int[11][12];
        POINT[] tmanposition = new POINT[32];
        tside = new IntegerWrapper(g_iSide);
        for (i = 0; i < 32; ++i) {
            tmanposition[i] = new POINT();
        }

        for (i = 0; i < 32; i++) {
            tmanposition[i] = new POINT();
            tmanposition[i].x = g_pointChessman[i].x;
            tmanposition[i].y = g_pointChessman[i].y;
        }
        for (i = 0; i < 11; i++) {
            for (j = 0; j < 12; j++) {
                tmap[i][j] = g_iChessmanMap[i][j];
            }
        }
        IntegerWrapper resultman = new IntegerWrapper(32);
        POINT resultpoint = new POINT();
        resultpoint.x = 0;
        resultpoint.y = 0;

        boolean flag = chess.Think(tmap, tmanposition, tside, resultman, resultpoint);
        if (flag) {
            Go(resultman, resultpoint);
            // 3D move
            g_3dchess.Go(resultman.getNumb(), resultpoint);
        } else {
            g_bEndGame = true;
        }
    }

    public boolean Go(IntegerWrapper man, POINT targetpoint) {
        int i, j; // news
        if (g_bEndGame) {
            return false;
        }

        if (g_MoveHistory.count >= MoveHistory.MAXMOVE) {
            g_MoveHistory.count = 0;
        }

        if (!chess.CanGo(g_iChessmanMap, man.getNumb(), g_pointChessman[man.getNumb()], targetpoint)) {
            return false;
        }
        g_MoveHistory.betaken[g_MoveHistory.count] = g_iChessmanMap[targetpoint.x][targetpoint.y];
        g_MoveHistory.man[g_MoveHistory.count] = man.getNumb();

        g_MoveHistory.from[g_MoveHistory.count].x = g_pointChessman[man.getNumb()].x;
        g_MoveHistory.from[g_MoveHistory.count].y = g_pointChessman[man.getNumb()].y;

        g_MoveHistory.to[g_MoveHistory.count].x = targetpoint.x;
        g_MoveHistory.to[g_MoveHistory.count].y = targetpoint.y;
        g_MoveHistory.count++;

        if (g_iChessmanMap[targetpoint.x][targetpoint.y] != 32) {
            g_pointChessman[g_iChessmanMap[targetpoint.x][targetpoint.y]].x = 0;
        }

        POINT from = new POINT();
        POINT to = new POINT();
        POINT oldselect = new POINT();

        from.x = g_pointBoxFrom.x;
        from.y = g_pointBoxFrom.y;

        to.x = g_pointBoxTo.x;
        to.y = g_pointBoxTo.y;

        g_pointBoxFrom.x = g_pointChessman[man.getNumb()].x;
        g_pointBoxFrom.y = g_pointChessman[man.getNumb()].y;

        g_pointBoxTo.x = targetpoint.x;
        g_pointBoxTo.y = targetpoint.y;

        oldselect.x = g_pointChessman[man.getNumb()].x;
        oldselect.y = g_pointChessman[man.getNumb()].y;

        g_pointChessman[man.getNumb()].x = targetpoint.x;
        g_pointChessman[man.getNumb()].y = targetpoint.y;

        FixManMap(g_iChessmanMap, g_pointChessman);

        g_iChessmanSelect = 32;
        if (g_iSide == 1) {
            g_iSide = 0;
        } else {
            g_iSide = 1;
        }

        for (i = 0; i < 11; i++) {
            for (j = 0; j < 12; j++) {
                POINT pt = new POINT(i, j);
                if (chess.CanGo(g_iChessmanMap, man.getNumb(), g_pointChessman[man.getNumb()], pt)) {
                    if (!g_bCanMove[i][j]) {
                        g_bCanMove[i][j] = true;
                        //ShowPoint(&hdc,pt);
                    }
                } else {
                    if (g_bCanMove[i][j]) {
                        g_bCanMove[i][j] = false;
                        //ShowPoint(&hdc,pt);
                    }
                }
            }
        }

        if (g_pointChessman[ChessAlgorithm.FistOfSide[g_iSide]].x == 0) {
            g_bEndGame = true;
            return true;
        }
        if (g_iComputerSide == g_iSide && !g_bEndGame) {
            Think();
        }
        return true;
    }

    public void OnLButtonDown(POINT point) {
        int i, j;
        if (g_bEndGame) {
            // message game over
        } else {
            int k = 0;
            if (g_iComputerSide == 0) {
                k = 1;
            }
            if (ChessAlgorithm.SideOfMan[g_iChessmanMap[point.x][point.y]] == k) {
                POINT p = new POINT();
                if (g_iChessmanSelect != 32) {
                    p.x = g_pointChessman[g_iChessmanSelect].x;
                    p.y = g_pointChessman[g_iChessmanSelect].y;
                }
                g_iChessmanSelect = g_iChessmanMap[point.x][point.y];

                for (i = 0; i < 11; i++) {
                    for (j = 0; j < 12; j++) {
                        POINT pt = new POINT(i, j);
                        if (chess.CanGo(g_iChessmanMap, g_iChessmanSelect, g_pointChessman[g_iChessmanSelect], pt)) {
                            if (!g_bCanMove[i][j]) {
                                g_bCanMove[i][j] = true;
                                //ShowPoint(&hdc,pt);
                            }
                        } else {
                            if (g_bCanMove[i][j]) {
                                g_bCanMove[i][j] = false;
                                //ShowPoint(&hdc,pt);
                            }
                        }
                    }
                }

                //ShowPoint(&hdc,g_pointChessman[g_iChessmanSelect]);
                //if(flag)
                //	ShowPoint(&hdc,p);
            } else if (g_iChessmanSelect != 32) {
                System.out.println("User move: "+g_iChessmanSelect+" to " +point.x+","+point.y);
                Go(new IntegerWrapper(g_iChessmanSelect), point);                
            }
        }
    }

    boolean FaceToPoint(POINT point) {
        if ((point.x) % BWA < SW || (point.x) % BWA > BWA - SW) {
            return false;
        }
        if ((point.y) % BWA < SW || (point.y) % BWA > BWA - SW) {
            return false;
        }
        POINT p = new POINT();
        p.x = (point.x) / BWA + 1;
        p.y = (point.y) / BWA + 1;
        if (p.x < 1 || p.x > 9 || p.y < 1 || p.y > 10) {
            return false;
        }
        point.x = p.x;
        point.y = p.y;
        return true;
    }

    // news
    public void OnNewgame() {
        OnFileNewRedfirst();
    }

    public void OnFileNewBlackfirst() {
        Reset();
        g_iComputerSide = 0; // 0:RED, 1:BLACK	
        Think();
    }

    public void OnFileNewRedfirst() {
        Reset();
        g_iComputerSide = 1; // computer is black
    }

    public void OnUndoMove() {
        int i, j;
        if (g_MoveHistory.count < 2) {
            return;
        }
        if (g_bEndGame) {
            // game over
            return;
        }
        for (i = g_MoveHistory.count - 1; i >= g_MoveHistory.count - 2; i--) {
            g_pointChessman[g_MoveHistory.man[i]].x = g_MoveHistory.from[i].x;
            g_pointChessman[g_MoveHistory.man[i]].y = g_MoveHistory.from[i].y;

            g_iChessmanSelect = g_MoveHistory.man[i];
            g_iChessmanMap[g_MoveHistory.from[i].x][g_MoveHistory.from[i].y] = g_MoveHistory.man[i];

            g_pointBoxFrom.x = g_MoveHistory.from[i].x;
            g_pointBoxFrom.y = g_MoveHistory.from[i].y;

            if (g_MoveHistory.betaken[i] != 32) {
                g_pointChessman[g_MoveHistory.betaken[i]].x = g_MoveHistory.to[i].x;
                g_pointChessman[g_MoveHistory.betaken[i]].y = g_MoveHistory.to[i].y;
            }
            g_iChessmanMap[g_MoveHistory.to[i].x][g_MoveHistory.to[i].y] = g_MoveHistory.betaken[i];

            g_pointBoxTo.x = g_MoveHistory.to[i].x;
            g_pointBoxTo.y = g_MoveHistory.to[i].y;
        }

        g_MoveHistory.count -= 2;
        g_bEndGame = false;

        for (i = 0; i < 11; i++) {
            for (j = 0; j < 12; j++) {
                g_bCanMove[i][j] = false;
            }
        }
    }

    // get set
    public boolean[][] getCanMoveMatrix() {
        return g_bCanMove;
    }

    public POINT[] getChessPoint() {
        return g_pointChessman;
    }

    public int[][] getChessMap() {
        return g_iChessmanMap;
    }

    // RED: 0, BLACK: 1
    public int getComputerColor() {
        return g_iComputerSide;
    }
    
    @Override
    public void exit() {
        
    }

    private int prevMouseX;
    private int prevMouseY;
    public void setMouseX(int x){
        prevMouseX = x;
    }
    
    public void setMouseY(int y){
        prevMouseY = y;
    }
    private boolean inSelectionMode;
    public void setIsSelectionMode(boolean mode){
        inSelectionMode = mode;
    }
    
    private static final int BUFSIZE = 512;
    private IntBuffer selectBuffer;
    private void startPicking(GL2 gl){
        int selectBuf[] = new int[BUFSIZE];
        selectBuffer = Buffers.newDirectIntBuffer(BUFSIZE);
        gl.glSelectBuffer(BUFSIZE, selectBuffer); 
 
        gl.glRenderMode(GL2.GL_SELECT); // switch to selection mode 
 
        gl.glInitNames(); // make an empty name stack 
 
        // save the original projection matrix 
        gl.glMatrixMode(GL2.GL_PROJECTION); 
        gl.glPushMatrix(); 
        gl.glLoadIdentity(); 
 
        // get the current viewport 
        int viewport[] = new int[4]; 
        gl.glGetIntegerv(GL2.GL_VIEWPORT, viewport, 0); 
 
        // create a 5x5 pixel picking volume near the cursor location 
        Global.getIns().glu.gluPickMatrix((double) prevMouseX, 
        (double) (viewport[3] - prevMouseY), 
        5.0, 5.0, viewport, 0); 
 
        double nr = 0.5;
        double fr = 3 * (NewCamera.dist - nr) + nr;
        Global.getIns().glu.gluPerspective(60, 1, nr, fr);
       
        gl.glMatrixMode(GL2.GL_MODELVIEW); // restore model view 

    }
    
    private void endPicking(GL2 gl){
        // restore original projection matrix 
        gl.glMatrixMode(GL2.GL_PROJECTION); 
        gl.glPopMatrix(); 
        gl.glMatrixMode(GL2.GL_MODELVIEW); 
        gl.glFlush(); 
 
        // return to normal rendering mode, and process hits 
        int numHits = gl.glRenderMode(GL2.GL_RENDER); 
        processHits(numHits,selectBuffer); 

        inSelectionMode = false;
        System.out.println("End picking");
    }
     public void processHits(int hits, IntBuffer buffer)
    {
      System.out.println("---------------------------------");
      System.out.println(" HITS: " + hits);
      int offset = 0;
      int names;
      float z1, z2;
      for (int i=0;i<hits;i++)
        {
          System.out.println("- - - - - - - - - - - -");
          System.out.println(" hit: " + (i + 1));
          names = buffer.get(offset); offset++;
          z1 = (float) (buffer.get(offset)& 0xffffffffL) / 0x7fffffff; offset++;
          z2 = (float) (buffer.get(offset)& 0xffffffffL) / 0x7fffffff; offset++;
          System.out.println(" number of names: " + names);
          System.out.println(" z1: " + z1);
          System.out.println(" z2: " + z2);
          System.out.println(" names: ");

          for (int j=0;j<names;j++)
            {
              System.out.print("       " + buffer.get(offset)); 
              //
              chessPiece[buffer.get(offset)].isChoose = true;
              //
              if (j==(names-1))
                System.out.println("<-");
              else
                System.out.println();
              offset++;
            }
          System.out.println("- - - - - - - - - - - -");
        }
      System.out.println("---------------------------------");
    }
     
     private void pickModels(GL2 gl){
         startPicking(gl);
         for (int i = 0; i < 32; i++) {
             gl.glPushName(i);
             chessPiece[i].draw(gl);
             gl.glPopName();
         }
         endPicking(gl);
     }
     
    @Override
    public void update(float dt) {
        for (int i = 0; i < 32; i++) {
            if(chessPiece[i].isChoose==true){
                chessPiece[i].isMoving=true;
                chessPiece[i].update(dt);
                chessPiece[i].moveTo(new POINT(5,0));
            }
        }
    }

    @Override
    public void render(GL2 gl) {
        board.draw(gl);
        if(inSelectionMode==true)
            pickModels(gl);
        for (int i = 0; i < 32; i++) {
            chessPiece[i].draw(gl);
        }
    }
    
}
